package com.astrob.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.astrob.NavFrameSDK.POIDescription;
import com.astrob.model.FavoriteData;
import com.astrob.model.FavoriteFileHandle;
import com.astrob.model.LonLat;
import com.astrob.naviframe.Start;
import com.astrob.nhcmap.R;

import java.io.File;
import java.util.ArrayList;

public class MapView extends View {

	Context mContext;

	public MapView(Context context) {
		super(context);
		mContext = context;
	}

	public MapView(Context context, AttributeSet attr) {
		super(context, attr);
		mContext = context;
	}

	private Car mCar = null;

	public void setCar(Car car) {
		mCar = car;
	}

	private void clearMapBmp() {
		if (mBitmapMap != null) {
			mBitmapMap.recycle();
			mBitmapMap = null;
		}
	}

	public static java.nio.ByteBuffer mBuffer = null;
	public static Bitmap mBitmapMap = null;
	public float ws = 1;
	public float hs = 1;
	public int y0_ = 0;
	private int mapWidth_ = 0;
	private int mapHeight_ = 0;
	
	public Bitmap mThisBitmapMap = null;

	public void resetBuffer() {
		mBuffer = null;
	}

	private void initBuffer() {
		if (mBuffer == null || mapWidth_ == 0) {
			clearMapBmp();
			int width = this.getWidth();
			int hight = this.getHeight();
			mapWidth_ = width;
			mapHeight_ = hight;

			if (width > 960 || hight > 960) {
				mapWidth_ = width / 2;
				mapHeight_ = hight / 2;
				mapWidth_ = mapWidth_ >> 2 << 2;
				mapHeight_ = mapHeight_ >> 2 << 2;
			}

			int[] location = new int[2];
			this.getLocationOnScreen(location);
			y0_ = location[1];
			ws = width * 1.0f / mapWidth_;
			hs = hight * 1.0f / mapHeight_;

			mBuffer = java.nio.ByteBuffer.allocate(mapWidth_ * mapHeight_ * 2);
			Start.getInstance().MapKit().setMapSize(mapWidth_, mapHeight_);

			if (mCar != null) {
				mCar.setMapsize(mapWidth_, mapHeight_);
			}

			clearMapBmp();
			mBitmapMap = Bitmap.createBitmap(mapWidth_, mapHeight_,
					Bitmap.Config.RGB_565);
		}
	}

	// 生成地图的范围，控制其他图层的icon显示
	double maxLon, maxLat, minLon, minLat;

	void setMapRegion() {
		maxLon = -180;
		maxLat = 0;
		minLon = 180;
		minLat = 90;
		Point pos = new Point(0, 0); // top-left

		for (int i = 0; i < 4; i++) {
			if (i == 1) {
				// top-right
				pos.x = mapWidth_;
				pos.y = 0;
			} else if (i == 2) {
				// bottom-left
				pos.x = 0;
				pos.y = mapHeight_;
			} else if (i == 3) {
				// bottom-right
				pos.x = mapWidth_;
				pos.y = mapHeight_;
			}

			LonLat ll = Start.getInstance().MapKit().XY2LL(pos);
			if (ll == null)
				break;
			double lon = ll.GetLon();
			double lat = ll.GetLat();
			if (maxLon < lon) {
				maxLon = lon;
			}
			if (maxLat < lat) {
				maxLat = lat;
			}
			if (minLon > lon) {
				minLon = lon;
			}
			if (minLat > lat) {
				minLat = lat;
			}
		}
	}

	@SuppressLint("DrawAllocation")
	@Override
	public void onDraw(Canvas canvas) {
		initBuffer();
		if (mIsMouseDown && mThisBitmapMap != null) {
			int dx = 0;
			int dy = 0;
			dx = mMouseDownPt.x - mRealMouseDownPt.x;
			dy = mMouseDownPt.y - mRealMouseDownPt.y;
			canvas.drawColor(Color.WHITE);
			canvas.drawBitmap(mThisBitmapMap, dx, dy, null);
			super.onDraw(canvas);
			return;
		}

		if (mZoomIndex != -1 && mThisBitmapMap != null) {
			canvas.drawColor(Color.WHITE);
			float scale = _newDist / _oldDist;
			if (scale == 1 || Start.getInstance().MapKit().checkZoomScale(scale)) {
				canvas.drawBitmap(mThisBitmapMap, 0, 0, null);
			} else {
				canvas.save();
				canvas.scale(scale, scale);
				int w = mThisBitmapMap.getWidth();
				int h = mThisBitmapMap.getHeight();
				int x = (int)(w* (scale - 1)/2);
				int y = (int)(h* (scale - 1)/2);
				canvas.drawBitmap(mThisBitmapMap, -x/scale, -y/scale, null);
				canvas.restore();
			}
			return;
		}

		mBuffer.rewind();
		// 显示地图
		Start.getInstance().MapKit().drawMap(1, mBuffer.array());
		try {
			mBitmapMap.copyPixelsFromBuffer(mBuffer);
		} catch (Exception e) {
			mapWidth_ = 0;
			initBuffer();
			return;
		}

		Matrix matrix = new Matrix();
		matrix.postScale(ws, ws);
		if (mThisBitmapMap != null) {
			mThisBitmapMap = null;
		}
		mThisBitmapMap = Bitmap
				.createBitmap(mBitmapMap, 0, 0, mBitmapMap.getWidth(),
						mBitmapMap.getHeight(), matrix, true);
//		canvas.drawBitmap(mThisBitmapMap, 0, 0, null);
		Drawable drawable= new BitmapDrawable(mContext.getResources(), mBitmapMap);
		if (drawable != null) {
			drawable.setBounds(0, 0, this.getWidth(), this.getHeight());
			drawable.draw(canvas);
		}

		setMapRegion();

		// 车标到目的地的红线
		drawLineCar2dest(canvas);

		// 显示车标
		if (mCar != null) {
			mCar.draw(mContext, canvas, ws, hs);
		}

		// tip poi 到 poimark 的连线
		drawLineTip2Poimark(canvas);

		// 显示TipMark
		drawTipMark(canvas);
		// 显示POIMark
		drawPOIMark(canvas);

		// 显示dest icon
		drawNavDest(canvas);

		// 显示收藏点
		drawFav(canvas);

		super.onDraw(canvas);
	}

	public ArrayList<FavoriteData> listDrawFavorite = new ArrayList<FavoriteData>();
	
	private void drawFav(Canvas canvas) {
		listDrawFavorite.clear();
		ArrayList<FavoriteData> listFavorite = FavoriteFileHandle.getInstance()
				.getListFavorite();
		int favcount = listFavorite.size();
		for (int i = 0; i < favcount; ++i) {
			FavoriteData data = listFavorite.get(i);
			if (data.countryID
					.compareToIgnoreCase("CN") != 0) {
				continue;
			}
			
			if (data.icon != 8) 
				continue;

			if (data.lon > maxLon || data.lat > maxLat || data.lon < minLon
					|| data.lat < minLat)
				continue;

			LonLat ll = new LonLat(data.lon, data.lat);
			Point favPos = new Point();
			favPos = Start.getInstance().MapKit().LL2XY(ll);

			if (favPos.x < 0 || favPos.x > mapWidth_ || favPos.y < 0
					|| favPos.y > mapHeight_)
				continue;
			
			File file0 = new File(data.getExInfo());
			if (!file0.exists())
				continue;
			
			listDrawFavorite.add(data);

			Bitmap bm = ((BitmapDrawable) getResources().getDrawable(
					R.drawable.poitonmapicon06)).getBitmap();

			int x = (int) (favPos.x * ws - bm.getWidth() / 2);
			int y = (int) (favPos.y * hs - bm.getHeight());
			canvas.drawBitmap(bm, x, y, new Paint());
		}

	}

	// tip poi 和poi mark的连线
	private void drawLineTip2Poimark(Canvas canvas) {
		if (!mTipLL.IsValid() || !mPOIMarkLL.IsValid())
			return;

		float[] ff = new float[4];

		Point e1 = Start.getInstance().MapKit().LL2XY(mPOIMarkLL);
		ff[0] = e1.x * ws;
		ff[1] = e1.y * ws;

		Point e2 = Start.getInstance().MapKit().LL2XY(mTipLL);
		ff[2] = e2.x * ws;
		ff[3] = e2.y * hs;

		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setColor(Color.RED);
		paint.setStyle(Paint.Style.STROKE);

		Path path = new Path();
		path.moveTo(ff[0], ff[1]);
		path.lineTo(ff[2], ff[3]);
		PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
		paint.setPathEffect(effects);
		canvas.drawPath(path, paint);

	}

	private void drawLineCar2dest(Canvas canvas) {
		if (Start.getInstance().MapKit().mNavDest == null || mCar == null) {
			return;
		}
		int size = Start.getInstance().MapKit().mNavDest.length;

		if (size < 1)
			return;

		int indexDest = size - 1;

		float[] ff = new float[4];

		LonLat destLL = new LonLat(
				Start.getInstance().MapKit().mNavDest[indexDest].pos.lon,
				Start.getInstance().MapKit().mNavDest[indexDest].pos.lat);
		Point d = Start.getInstance().MapKit().LL2XY(destLL);
		ff[0] = d.x * ws;
		ff[1] = d.y * hs;

		Point carpos = Start.getInstance().MapKit().LL2XY(mCar.getCarLL());
		ff[2] = carpos.x * ws;
		ff[3] = carpos.y * hs;

		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setColor(Color.RED);
		paint.setStrokeWidth((float) 3.0);
		canvas.drawLines(ff, paint);
	}

	private static ArrayList<Bitmap> favPIconList = new ArrayList<Bitmap>(); // 照片fav

	// 图片去色,返回灰度图片
	public static Bitmap toGrayscale(Bitmap bmpOriginal) {
		int width, height;
		height = bmpOriginal.getHeight();
		width = bmpOriginal.getWidth();

		Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,
				Bitmap.Config.RGB_565);
		Canvas c = new Canvas(bmpGrayscale);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(0);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		return bmpGrayscale;
	}

	private boolean mShowRoutePlanDests = true;

	public void setShowRoutePlanDests(boolean show) {
		mShowRoutePlanDests = show;
	}

	private void drawNavDest(Canvas canvas) {
		if (mShowRoutePlanDests && Start.getInstance().MapKit().mNavDest != null
				&& Start.getInstance().MapKit().mNavDest.length > 0) {
			int count = Start.getInstance().MapKit().mNavDest.length;
			int resId = R.drawable.destination;
			for (int i = 0; i < count; ++i) {
				LonLat poiLL = new LonLat(
						Start.getInstance().MapKit().mNavDest[i].pos.lon,
						Start.getInstance().MapKit().mNavDest[i].pos.lat);
				Point e = Start.getInstance().MapKit().LL2XY(poiLL);
				if (e.x < 0 || e.x > mapWidth_ || e.y < 0 || e.y > mapHeight_)
					continue;

				if (i == count - 1) {
					resId = R.drawable.destination;
				} else {
					resId = R.drawable.marker01 + i;
					if (resId > R.drawable.marker15) {
						resId = R.drawable.marker15;
					}
				}

				Bitmap bm = ((BitmapDrawable) getResources().getDrawable(resId))
						.getBitmap();
				int x = (int) (e.x * ws - bm.getWidth() / 2);
				int y = (int) (e.y * hs - bm.getHeight());
				canvas.drawBitmap(bm, x, y, null);
			}
		}
	}

	private void drawTipMark(Canvas canvas) {
		if (!mTipLL.IsValid()) {
			return;
		}

		Point e = Start.getInstance().MapKit().LL2XY(mTipLL);
		if (e.x < 0 || e.x > mapWidth_ || e.y < 0 || e.y > mapHeight_)
			return;

		Bitmap bm = ((BitmapDrawable) getResources().getDrawable(
				R.drawable.map_marker)).getBitmap();

		int x = (int) (e.x * ws - bm.getWidth() / 2);
		int y = (int) (e.y * hs - bm.getHeight());
		canvas.drawBitmap(bm, x, y, null);
	}

	private LonLat mPOIMarkLL = new LonLat();

	public void setPOIMarkLL(double dlon, double dlat) {
		mPOIMarkLL.SetLonLat(dlon, dlat);
	}

	private void drawPOIMark(Canvas canvas) {
		if (!mPOIMarkLL.IsValid()) {
			return;
		}

		Point e = Start.getInstance().MapKit().LL2XY(mPOIMarkLL);
		if (e.x < 0 || e.x > mapWidth_ || e.y < 0 || e.y > mapHeight_)
			return;

		Bitmap bm = ((BitmapDrawable) getResources().getDrawable(
				R.drawable.map_marker2)).getBitmap();

		int x = (int) (e.x * ws - bm.getWidth() / 2);
		int y = (int) (e.y * hs - bm.getHeight());
		canvas.drawBitmap(bm, x, y, null);
	}

	private Point mMouseDownPt = new Point();
	private Point mRealMouseDownPt = new Point();
	private long mLastMilliseconds = 0;
	private static final int MOVEMAP_JUDGE_FACTOR = 13;
	private boolean mIsMouseDown = false;
	private boolean mIsMoving = false;
	private float mTouchdx = 0;
	
	private float mZoomIndex = -1; // 
	float _newDist = 0;
	float _oldDist = 0;

	public boolean onMouseEvent(MotionEvent event) {
		int actionEvent = event.getAction();
		int pointerCount = event.getPointerCount();

		if (pointerCount == 1) {
			int y = (int) event.getY() - y0_;
			if (y < 0)
				return false;
			if (actionEvent == MotionEvent.ACTION_DOWN) {
				mouseDown((int) event.getX(), y);
				mTouchdx = 0;
				mZoomIndex = -1;
			} else if (actionEvent == MotionEvent.ACTION_MOVE) {
				mouseMove((int) event.getX(), y);
			} else if (actionEvent == MotionEvent.ACTION_UP) {
				mouseUp((int) event.getX(), y);
				mTouchdx = 0;
				mZoomIndex = -1;
			}
		} else if (pointerCount == 2) {
			mIsMouseDown = false;
			actionEvent = event.getAction() & MotionEvent.ACTION_MASK;
			if (actionEvent == MotionEvent.ACTION_POINTER_DOWN) {
				// 进不来
				mZoomIndex = 1;
				mTouchdx = (float) Start.getInstance().spacing(event);
				if (mTouchdx > 10f) {
					// midPoint(mid, event);
				}
				_newDist = mTouchdx;
				_oldDist = mTouchdx;
			} else if (actionEvent == MotionEvent.ACTION_MOVE) {
				float newDist = (float)Start.getInstance().spacing(event);
				if (newDist > 10f) {
					_newDist = newDist;
				}
			} else if (actionEvent == MotionEvent.ACTION_POINTER_UP) {
				if (_oldDist > 0) {
					Start.getInstance().MapKit().zoomScale(_newDist / _oldDist);
				}
				
				mTouchdx = 0;
				mZoomIndex = -1;
			}
		}

		return super.onTouchEvent(event);
	}

	public boolean mouseDown(int x, int y) {
		needTip = false;
		mIsMouseDown = false;
		mIsMoving = false;
		long currentMilliseconds = System.currentTimeMillis();
		long xMilliseconds = currentMilliseconds - mLastMilliseconds;
		if (xMilliseconds < 500) {
			return false;
		}
		mLastMilliseconds = System.currentTimeMillis();

		mMouseDownPt.set(x, y);
		mRealMouseDownPt.set(x, y);
		mIsMouseDown = true;

		return true;
	}

	public void mouseMove(int x, int y) {
		if (!mIsMouseDown)
			return;

		if ((Math.abs(mMouseDownPt.x - x) >= MOVEMAP_JUDGE_FACTOR * ws)
				|| (Math.abs(mMouseDownPt.y - y) >= MOVEMAP_JUDGE_FACTOR * hs)) {
			if (!mIsMoving) {
				mIsMoving = true;
			}
			Start.getInstance().MapKit().moveMap((int) ((x - mMouseDownPt.x) / ws),
					(int) ((y - mMouseDownPt.y) / hs));
			mMouseDownPt.set(x, y);
		}
	}

	public void mouseUp(int x, int y) {
		if (!mIsMouseDown)
			return;

		needTip = false;
		mIsMouseDown = false;
		if (mIsMoving) {
			mMouseDownPt.set(0, 0);
			needTip = false;
			mIsMoving = false;
		} else {
			needTip = true;
			mTipPoint.set((int) (x / ws), (int) (y / hs));
			mTipLL = Start.getInstance().MapKit().XY2LL(mTipPoint);
			changeTipLL();
			Start.getInstance().MapKit().setMapCenter(mTipLL);
		}
	}

	public boolean needTip = false;
	private Point mTipPoint = new Point();
	private LonLat mTipLL = new LonLat();

	public LonLat getTipLL() {
		return mTipLL;
	}

	public void setTipLL(LonLat tipLL) {
		mTipLL = tipLL;
	}

	void changeTipLL() {
		Start.getInstance().MapKit().mTipPoiList = Start.getInstance().MapKit().getNearPoi(
				mTipLL, true);
		if (Start.getInstance().MapKit().mTipPoiList.size() < 1)
			return;
		POIDescription data = Start.getInstance().MapKit().mTipPoiList.get(0);
		if (data.pcode.length > 0) {
			mTipLL.SetLonLat(data.position.lon, data.position.lat);
		}
	}


}
